package rm.metrology.server;

import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.Set;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;

import rm.metrology.shared.AbstractEntity;
import rm.metrology.shared.CostEntity;
import rm.metrology.shared.LocationEnum;
import rm.metrology.shared.LogEntity;
import rm.metrology.shared.MetroEntity;
import rm.metrology.shared.UncertaintyEntity;
import rm.metrology.shared.UserEntity;
import rm.metrology.shared.ValidationException;

import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.util.DAOBase;

public class BaseDAO extends DAOBase {

	static {
		ObjectifyService.register(UserEntity.class);
		ObjectifyService.register(CostEntity.class);
		ObjectifyService.register(UncertaintyEntity.class);
		ObjectifyService.register(MetroEntity.class);
	}
		
	static {
		Properties properties = new Properties();
		InputStream is = null;
		try {
			is = ClassLoader.getSystemResourceAsStream("rm/metrology/server/BaseDAO.properties");
		    properties.load(is);
		    is.close();
		} catch (IOException e) {
			throw new IllegalArgumentException(e);
		}
		EMAIL_HEADER = properties.getProperty("email.header");
		EMAIL_FOOTER = properties.getProperty("email.footer");
		EMAIL_ADDRESS_DEFAULT = properties.getProperty("email.address.default");
		EMAIL_SUBJECT_PREFIX = properties.getProperty("email.subject.prefix");
		properties.clear();
	}

	private static final Validator fValidator = 
			Validation.byDefaultProvider().configure().buildValidatorFactory().getValidator();
	
	// throws ValidationException if validation errors present.
	protected static final <T> void validate(T entity) {
		Set<ConstraintViolation<T>> errors = fValidator.validate(entity);
		if (errors.size() > 0) {
			ValidationException ex = new ValidationException();
			for (ConstraintViolation<T> c : errors) {
				ex.addError(c.getInvalidValue(), c.getMessage());
			}
			throw ex;
		}
	}
	
	protected static final void validateNationalUser(UserEntity user) {
		if (user.getLocationType() == LocationEnum.NATIONAL) return;
		String msg = LocationEnum.NATIONAL.toString() 
						+ ": location users ONLY allowed, your location: "
						+ user.getLocationType().toString();
		throw new IllegalStateException(msg);
	}
	
	protected StringBuilder getLogs(AbstractEntity e) {
		StringBuilder builder = new StringBuilder(2048);
		builder.append("<table cellspacing='8' style='margin:8px;' ");
		builder.append("<tr><td>Date/Time</td><td>Staff</td><td>Log Message</td></tr>");
		for (LogEntity l : e.getLogs()) {
			builder.append("<tr><td>")
				   .append(l.getCreatedTime()).append("</td><td>")
				   .append(l.getStaff()).append("</td><td>")
				   .append(l.getComment())
				   .append("</td></tr>");
		}
		builder.append("</table>");
		return builder;
	}
	
//	protected static <T> List<T> getChildren(Object parent, Class<T> clazz) {
//		return ObjectifyService.begin().query(clazz).ancestor(parent).order("fCreatedAt").list();
//	}

	protected final static boolean emailClient(String clientEmail, String subject, String body) {
		return sendEmail(clientEmail, subject, body);
	}
	
	protected final static boolean emailStaff(String subject, String body) {
		return sendEmail(EMAIL_ADDRESS_DEFAULT, subject, body);
	}
	
	protected final static boolean sendEmail(String toEmail, String subject, String body) {
		Properties props = new Properties();
        Session session = Session.getDefaultInstance(props, null);
        try {
			InternetAddress from = new InternetAddress(EMAIL_ADDRESS_DEFAULT);
			InternetAddress to = new InternetAddress(toEmail);
            Message msg = new MimeMessage(session);
            msg.setFrom(from);
            msg.addRecipient(Message.RecipientType.TO, to);
            msg.setSubject(subject);
            msg.setText(body);
            Transport.send(msg);
            return true;
        } catch (MessagingException e) {
            return false;
        }
	}

	protected final static String formatDate(Long time) {
		return DATE_FORMAT.format(new Date(time));
	}
	
	protected final static String getOperator() {
		if (USER_SVC.getCurrentUser() == null) {
			return "no.staff@trade.gov.mv";
		}
		return USER_SVC.getCurrentUser().getEmail();
	}
	
	protected final static void assertNotNulls(Object... objects) {
		for (Object o : objects) {
			if (o == null) {
				throw new IllegalArgumentException("Argument cannot be null");
			}
		}
	}
	
	protected static String EMAIL_HEADER, EMAIL_FOOTER, 
							EMAIL_ADDRESS_DEFAULT,
							EMAIL_SUBJECT_PREFIX;
	
	private final static UserService USER_SVC = UserServiceFactory.getUserService();
	
	private final static DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MMM-dd HH:mm");  

}
